Skip to content

[PD]: Support HiCache prefetching and pd-incremental transfer on decode side - #26227

Merged
ShangmingCai merged 18 commits into
mainfrom
hicache/decode-hicache
Jun 2, 2026
Merged

ShangmingCai merged 18 commits into
mainfrom
hicache/decode-hicache

Conversation

@hzh0425

@hzh0425 hzh0425 commented May 24, 2026

Copy link
Copy Markdown
Collaborator

Motivation

Roadmap: #21846#21703
Still in progress, TODO:

  • Precisely control token budget
  • Improve parallelization between HiCache transfer and PD transfer
  • Large-scale, systematic testing of PD + HiCache, Provide performance benefit metrics.
  • Support Unified Radix Tree

Modifications

Accuracy Tests

Speed Tests and Profiling

Qwen32B + PD + HiCache + Mooncake

Round Prompt Length No Decode Radix TTFT Decode L2+L3 TTFT TTFT Reduction No Radix Hit Rate L2+L3 Hit Rate Hit Rate Gain
0 4K 2.29s 1.59s 30.9% 0.000 0.000 +0.000
1 16K 7.25s 5.56s 23.3% 0.250 0.750 +0.500
2 28K 12.72s 9.19s 27.8% 0.571 0.857 +0.286
3 40K 18.01s 11.93s 33.8% 0.700 0.900 +0.200
4 52K 23.40s 12.52s 46.5% 0.769 0.923 +0.154
5 64K 28.50s 15.18s 46.7% 0.812 0.937 +0.125
Metric No Decode Radix Decode L2+L3 Change
Average TTFT 15.36s 9.33s -39.3%
P90 TTFT 36.46s 19.30s -47.1%
P99 TTFT 48.87s 23.51s -51.9%
Cache Hit Rate 0.686 0.882 +19.6 percentage points
Average TPOT / ITL 40.31ms 41.32ms +2.5%
P90 TPOT / ITL 52.62ms 53.63ms +1.9%
Output Throughput 183.47 tok/s 185.70 tok/s +1.2%

Checklist

Review and Merge Process

  1. Ping Merge Oncalls to start the process. See the PR Merge Process.
  2. Get approvals from CODEOWNERS and other reviewers.
  3. Trigger CI tests with comments or contact authorized users to do so.
    • Common commands include /tag-and-rerun-ci, /tag-run-ci-label, /rerun-failed-ci
  4. After green CI and required approvals, ask Merge Oncalls or people with Write permission to merge the PR.

CI States

Latest PR Test (Base): ✅ Run #26766211033
Latest PR Test (Extra): ✅ Run #26766210099

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements hierarchical cache (HiCache) support for the disaggregated decode path, enabling KV cache restoration across L1 (device), L2 (host), and L3 (storage) layers. It introduces the DecodePrefixMatch and HiCacheRestoreResult structures to manage cache hit metadata and the state of local restoration. The core logic involves querying storage hit lengths during prefix matching and a multi-phase state machine in the decode manager to drive prefetching and load-back operations. Review feedback identifies critical performance bottlenecks caused by distributed synchronization (all_reduce) occurring within per-request loops, which should be batched or moved outside the loops. Additionally, the reviewer noted redundant prefix matching logic and potential throughput issues due to the serialization of L2-to-L1 restore operations.

Comment thread python/sglang/srt/mem_cache/hiradix_cache.py
Comment thread python/sglang/srt/disaggregation/decode.py Outdated
Comment thread python/sglang/srt/disaggregation/decode.py Outdated
Comment thread python/sglang/srt/disaggregation/decode.py Outdated
Comment thread python/sglang/srt/disaggregation/decode.py
Comment thread python/sglang/srt/disaggregation/decode.py Outdated
Comment thread python/sglang/srt/mem_cache/hiradix_cache.py
@github-actions github-actions Bot added the hicache Hierarchical Caching for SGLang label May 28, 2026
if self.scheduler.metrics_reporter.enable_metrics:
self.scheduler.metrics_collector.increment_transfer_failed_reqs()
continue
elif poll == KVPoll.Success:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why we change it from elif to if?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change back

Comment on lines +1594 to +1598
if poll == KVPoll.Failed:
try:
decode_req.kv_receiver.failure_exception()
except Exception as e:
error_message += f" with exception {e}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What could be the reason of HiCacheRestoreResult.FAILED? Should we append some error_message detail as well?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a failed log in decode_hicache_mixin

Comment thread python/sglang/srt/disaggregation/decode_hicache_mixin.py

@ShangmingCai ShangmingCai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No other comments.

Co-authored-by: Shangming Cai <csmthu@gmail.com>
Co-authored-by: 晟海 <huangtingwei.htw@antgroup.com>
@hzh0425
hzh0425 force-pushed the hicache/decode-hicache branch from 67027ae to 00c2ced Compare June 1, 2026 15:57
@hzh0425

hzh0425 commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator Author

/rerun-test test/registered/disaggregation/test_disaggregation_decode_radix_cache.py

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Results for /rerun-test test/registered/disaggregation/test_disaggregation_decode_radix_cache.py:

🚀 8-gpu-h20 (1 test): ✅ View workflow run

cd test/ && python3 registered/disaggregation/test_disaggregation_decode_radix_cache.py

operation
)
storage_hit_count_tensor = torch.tensor(storage_hit_count, dtype=torch.int)
self._all_reduce_attn_groups(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could revisit this in the future if this per-request all_reduce causes a performance issue for large batch sizes.

@ShangmingCai

Copy link
Copy Markdown
Collaborator

CI has passed.
image
image

@ShangmingCai
ShangmingCai merged commit 3e993f6 into main Jun 2, 2026
251 of 276 checks passed
@ShangmingCai
ShangmingCai deleted the hicache/decode-hicache branch June 2, 2026 07:40
mqhc2020 pushed a commit to mqhc2020/sglang that referenced this pull request Jun 2, 2026
…de side (sgl-project#26227)

Co-authored-by: huangtingwei <141888744+huangtingwei9988@users.noreply.github.com>
Co-authored-by: Shangming Cai <csmthu@gmail.com>
Co-authored-by: 晟海 <huangtingwei.htw@antgroup.com>
hanming-lu pushed a commit that referenced this pull request Jun 3, 2026
…de side (#26227)

Co-authored-by: huangtingwei <141888744+huangtingwei9988@users.noreply.github.com>
Co-authored-by: Shangming Cai <csmthu@gmail.com>
Co-authored-by: 晟海 <huangtingwei.htw@antgroup.com>
@weibingo

weibingo commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@hzh0425 I have a question: when the KV cache of the decode node is in L3, even if the cache hits in L3, it still needs to be pulled from L3 to the CPU, and then from the CPU to the GPU. The time spent in this process should be greater than the overhead of transferring from P to D, right?

@ShangmingCai

Copy link
Copy Markdown
Collaborator

@hzh0425 I have a question: when the KV cache of the decode node is in L3, even if the cache hits in L3, it still needs to be pulled from L3 to the CPU, and then from the CPU to the GPU. The time spent in this process should be greater than the overhead of transferring from P to D, right?

@weibingo Yeah, but the matched prefix KV fetching could be overlapped with the computing and transferring of the incremental part, so this design is better for multi-turn conversations and agentic use cases.

fzyzcjy added a commit that referenced this pull request Jun 12, 2026
The conditional re-match for requests whose reset_for_retract cleared
last_node was introduced on main by PR #26227 together with the
TODO(retraction) note in _pre_alloc. The merge of main into the
stateless-scheduler branch kept the TODO but dropped the conditional,
unconditionally passing tree_cache=None on the decode-radix path, so
retracted-resumed requests lost prefix reuse. Restore the base behavior
and its explanatory comment.
Chronostasys pushed a commit to MindLab-Research/sglang that referenced this pull request Aug 24, 2026
…de side (sgl-project#26227)

Co-authored-by: huangtingwei <141888744+huangtingwei9988@users.noreply.github.com>
Co-authored-by: Shangming Cai <csmthu@gmail.com>
Co-authored-by: 晟海 <huangtingwei.htw@antgroup.com>
jakki-amd pushed a commit to jakki-amd/sglang that referenced this pull request Sep 9, 2026
…de side (sgl-project#26227)

Co-authored-by: huangtingwei <141888744+huangtingwei9988@users.noreply.github.com>
Co-authored-by: Shangming Cai <csmthu@gmail.com>
Co-authored-by: 晟海 <huangtingwei.htw@antgroup.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants